How I Programmed this Blog
Mircheski Petar
February 04, 2022
4 min read
After coming to Japan during the winter holidays since I had too much free time I decided on starting my own website and blog. Having previous experience with working with React and Next.js I decided to take up on the challenge of working on some personal hobby project.
Theming
Having first hand experience using Material-UI and using it extensively for the past 2 years I wanted to switch things and learn a new framework or technology for this website. I chose Chakra-UI for this project because of it's simplicity and large palette of components that are available. The benefits of using Chakra-UI are tremendous, such as:
- It's a modular library
- Implementing style-props.
- Responsive styles.
- It comes with Light and Dark mode management hooks.
- Big enough community to be an asset to my knowledge.
- Excellent integration with Next.js.
export const VideoGridItem: FC<Props> = ({ title, videoId, link }) => {
return (
<GridItem shadow="dark-lg" rounded="lg">
<Box mx="auto" maxW="2xl">
<Link display="block" fontWeight="bold" fontSize="2xl" href={link}>
<Img
roundedTop="lg"
w="full"
h={64}
src={`https://img.youtube.com/vi/${videoId}/hqdefault.jpg`}
alt="Article"
/>
</Link>
<Box p={6} display="flex">
<Link
display="block"
fontWeight="bold"
fontSize="2xl"
mt={2}
href={link}
>
{title}
</Link>
</Box>
</Box>
</GridItem>
);
};
Content Management
This blog is built using MDX and ContentLayer, this serves as a great alternative to keeping the blog-posts inside a markup file such as a json-file or maintaining a big code base that is based on a content management tool such as Strapi.js, WordPress or Ghost.js. The file structure of the posts is managed by ContentLayer which manages the .mdx files that have a predefined structure. Each .mdx file contains the following structure:
---
title: '2021 Year in Review'
publishedAt: '2021-12-30'
summary: 'Highlights and reflections on 2021 and a look forward to 2022.'
image: '/static/2021_year_in_review/2021.jpg'
---
Using the ContentLayer I can easily parse the .mdx files their meta-data add calculated attributes to the blog posts such as reading time and the url slug and display the data easily inside the blog page and blog posts.
const computedFields: ComputedFields = {
readingTime: { type: 'json', resolve: (doc) => readingTime(doc.body.raw) },
wordCount: {
type: 'number',
resolve: (doc) => doc.body.raw.split(/\s+/gu).length,
},
slug: {
type: 'string',
resolve: (doc) => doc._raw.sourceFileName.replace(/\.mdx$/, ''),
},
};
ContentLayer generates typescript types making the coding experience more type-safe and sane. It also has the ability to easily integrate with the rehype the Markdown HTML processor in order to more easily parse the .mdx files. The rehype extensions that I use are the rehype-gfm (github flavored markdown css), the rehype-math which allows me to input latex-like math expressions and rehype-code-titles and rehype-prism which are extensions that format markdown code-blocks with a title and add the ability to format the code inside the code-blocks with a beautiful theme.
const Blog = defineDocumentType(() => ({
name: 'Blog',
filePathPattern: 'blog/*.mdx',
bodyType: 'mdx',
fields: {
title: { type: 'string', required: true },
publishedAt: { type: 'string', required: true },
summary: { type: 'string', required: true },
image: { type: 'string', required: true },
},
computedFields,
}));
const contentLayerConfig = makeSource({
contentDirPath: 'data',
documentTypes: [Blog],
mdx: {
remarkPlugins: [remarkGfm, remarkMath],
rehypePlugins: [
rehypeSlug,
rehypeCodeTitles,
rehypeKatex,
rehypePrism,
[
rehypeAutolinkHeadings,
{
properties: {
className: ['anchor'],
},
},
],
],
},
});
MDX allows me to directly define JSX code inside the markdown posts. This is needed to explicitly define images, charts and other useful components to make the blog more aesthetically appealing.
---
title: '2021 Year in Review'
publishedAt: '2021-12-30'
summary: 'Highlights and reflections on 2021 and a look forward to 2022.'
image: '/static/2021_year_in_review/2021.jpg'
---
<Image
alt={`2019 Year in Review`}
src={`/static/2021_year_in_review/2021.jpg`}
width={1200}
height={630}
priority
/>
Using Next.js with ContentLayer
Using Next.js gives us the ability to programmatically create static html documents using the data that ContentLayer serves us. This increases the performance of the web-site and also allows us to use the native getStaticProps() function that Next.js has. Using the post-slug we can build the structure of the blog very easily:
import { GetStaticPaths, GetStaticProps } from 'next';
import { allBlogs } from '.contentlayer/data';
import type { Blog } from '.contentlayer/types';
export const getStaticProps: GetStaticProps = async ({ params }) => {
const post = allBlogs.find((post: Blog) => post.slug === params?.slug);
return { props: { post } };
};
Summary
- Next.js, ContentLayer and MDX work excellently together.
- The Blog has low over-head since no back-end and database are needed.
- The code strcuture is flexible and ergonomic.
- ContentLayer is a little difficult to use because of the lack of documentation at the time this blog was made but there are a lot of examples on the internet that people can draw inspirations from.
- Open-sourcing is fun 🚀.